﻿// ------------------------------------------------------------------------
// 版权信息
// 版权归重庆虫儿飞科技有限公司所有。
// 所有权利保留。
// 官方网站：https://netokit.com
// 许可证信息
// Neto.Kit 项目主要遵循 MIT 许可证和 Apache 许可证（版本 2.0）进行分发和使用。
// 许可证的完整文本可以在源代码树根目录中的 LICENSE-APACHE 和 LICENSE-MIT 文件中找到。
// 
// 使用条款
// 使用本代码应遵守相关法律法规和许可证的要求。
// 
// 免责声明
// 对于因使用本代码而产生的任何直接、间接、偶然、特殊或后果性损害，我们不承担任何责任。
// 
// 其他重要信息
// Neto.Kit 项目的版权、商标、专利和其他相关权利均受相应法律法规的保护。
// 有关 Neto.Kit 项目的其他详细信息，请参阅位于源代码树根目录中的 COPYRIGHT 和 DISCLAIMER 文件。
// 
// 更多信息
// 请访问 https://netokit.com 获取更多关于 Neto.Kit 项目的许可证和版权信息。
// ------------------------------------------------------------------------

#region

using Microsoft.Extensions.Caching.Memory;

#endregion

namespace Neto.Caches;

/// <summary>
///     内存缓存扩展
/// </summary>
public static class MemoryCacheExtension
{
    /// <summary>
    ///     设置缓存
    /// </summary>
    /// <param name="obj">缓存数据</param>
    /// <param name="cacheKey">缓存key</param>
    /// <param name="options">缓存选项</param>
    /// <returns></returns>
    public static void SetMemoryCache(this object obj, string cacheKey,
        MemoryCacheEntryOptions? options = null)
    {
        var memoryCache = App.GetService<IMemoryCache>();
        options = MemoryCacheHelper.GetDefaultOptions(options);

        memoryCache.Set(cacheKey, obj, options);
        MemoryCacheHelper._keys.Add(cacheKey); // 更新键集合
    }

    /// <summary>
    ///     设置缓存
    /// </summary>
    /// <param name="obj">缓存数据</param>
    /// <param name="cachekey">缓存key</param>
    /// <param name="options">缓存选项</param>
    /// <returns></returns>
    public static async Task SetMemoryCacheAsync(this object obj, string cachekey,
        MemoryCacheEntryOptions? options = null)
    {
        await Task.Run(() => SetMemoryCache(obj, cachekey, options));
    }

    // /// <summary>
    // ///     获取内存缓存
    // /// </summary>
    // /// <typeparam name="TEntity"></typeparam>
    // /// <param name="cacheKey">缓存key</param>
    // /// <returns></returns>
    // public static TEntity? GetMemoryCache<TEntity>(this string cacheKey)
    // {
    //     var memoryCache = App.GetService<IMemoryCache>();
    //     var state = memoryCache.TryGetValue(cacheKey, out TEntity? datas);
    //     return state ? datas : default;
    // }
    //
    // /// <summary>
    // ///     获取内存缓存
    // /// </summary>
    // /// <typeparam name="TEntity"></typeparam>
    // /// <param name="cacheKey">缓存key</param>
    // /// <returns></returns>
    // public static async Task<TEntity?> GetMemoryCacheAsync<TEntity>(this string cacheKey)
    // {
    //     return await Task.Run(() => GetMemoryCache<TEntity>(cacheKey));
    // }


    /// <summary>
    ///     获取缓存数据
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="cacheKey">缓存Key</param>
    /// <param name="func">方法</param>
    /// <param name="options">缓存配置选项</param>
    /// <returns>返回的实体对象</returns>
    public static TEntity? GetMemoryCache<TEntity>(this string cacheKey, Func<TEntity>? func = null,
        MemoryCacheEntryOptions? options = null)
    {
        var memoryCache = App.GetService<IMemoryCache>();
        var state = memoryCache.TryGetValue(cacheKey, out TEntity? obj);
        if (state) return obj;
        if (func == null) return default;
        var entities2 = func.Invoke();

        if (entities2 == null) return entities2;
        if (options == null)
        {
            options = MemoryCacheHelper.GetDefaultOptions(options);
            options.SlidingExpiration = new TimeSpan(0, 10, 0);
        }

        entities2.SetMemoryCache(cacheKey, options);
        MemoryCacheHelper._keys.Add(cacheKey); // 更新键集合

        return entities2;
    }

    /// <summary>
    ///     获取缓存数据
    /// </summary>
    /// <typeparam name="TEntity"></typeparam>
    /// <param name="cacheKey">缓存Key</param>
    /// <param name="func">方法</param>
    /// <param name="options">缓存配置选项</param>
    /// <param name="token">取消令牌</param>
    /// <returns>返回的实体对象</returns>
    public static async Task<TEntity?> GetMemoryCacheAsync<TEntity>(this string cacheKey,
        Func<Task<TEntity>>? func = null,
        MemoryCacheEntryOptions? options = null, CancellationToken token = default)
    {
        var memoryCache = App.GetService<IMemoryCache>();
        var state = memoryCache.TryGetValue(cacheKey, out TEntity? obj);
        if (state) return obj;
        if (func == null) return default;
        var entities2 = await func.Invoke();

        if (entities2 == null) return entities2;
        if (options == null)
        {
            options = MemoryCacheHelper.GetDefaultOptions();
            options.AbsoluteExpiration = DateTimeOffset.Now.AddMinutes(10);
        }

        await entities2.SetMemoryCacheAsync(cacheKey, options);
        MemoryCacheHelper._keys.Add(cacheKey); // 更新键集合

        return entities2;
    }


    /// <summary>
    ///     移除内存缓存
    /// </summary>
    /// <param name="cacheKey"></param>
    public static void RemoveMemoryCache(this string cacheKey)
    {
        var memoryCache = App.GetService<IMemoryCache>();
        memoryCache.Remove(cacheKey);
        MemoryCacheHelper._keys.Remove(cacheKey); // 更新键集合
    }

    /// <summary>
    ///     移除内存缓存
    /// </summary>
    /// <param name="cacheKey"></param>
    public static async Task RemoveMemoryCacheAsync(this string cacheKey)
    {
        await Task.Run(() => RemoveMemoryCache(cacheKey));
    }

    /// <summary>
    ///     是否存在缓存Key
    /// </summary>
    /// <param name="cacheKey"></param>
    public static bool ExistMemoryCache(this string cacheKey)
    {
        var memoryCache = App.GetService<IMemoryCache>();
        return memoryCache.TryGetValue(cacheKey, out _);
    }

    /// <summary>
    ///     是否存在缓存Key
    /// </summary>
    /// <param name="cacheKey"></param>
    public static async Task<bool> ExistMemoryCacheAsync(this string cacheKey)
    {
        return await Task.Run(() => ExistMemoryCache(cacheKey));
    }


    /// <summary>
    ///     注册缓存项被驱逐时的回调函数
    /// </summary>
    /// <param name="options"></param>
    /// <returns></returns>
    public static MemoryCacheEntryOptions RegisterPostEvictionCallback(this MemoryCacheEntryOptions options)
    {
        options.RegisterPostEvictionCallback((k, v, reason, state) =>
        {
            // 当缓存项被驱逐时，从键集合中移除
            MemoryCacheHelper._keys.Remove(k.ToString());
        });
        return options;
    }

    #region IQueryable

    /// <summary>
    ///     获取内存缓存
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="cacheKey">缓存key</param>
    /// <typeparam name="TEntity"></typeparam>
    /// <returns></returns>
    public static List<TEntity>? GetMemoryCache<TEntity>(this IQueryable<TEntity> entities, string cacheKey)
    {
        return GetMemoryCache<List<TEntity>>(cacheKey);
    }

    /// <summary>
    ///     获取内存缓存
    /// </summary>
    /// <param name="entities"></param>
    /// <param name="cacheKey"></param>
    /// <typeparam name="TEntity"></typeparam>
    /// <returns></returns>
    public static async Task<List<TEntity>?> GetMemoryCacheAsync<TEntity>(this IQueryable<TEntity> entities,
        string cacheKey)
    {
        return await GetMemoryCacheAsync<List<TEntity>>(cacheKey);
    }

    #endregion
}